import streamlit as st
import pandas as pd
import numpy as np
import os
from datetime import datetime

# 设置Pandas Styler的最大渲染元素数
pd.set_option("styler.render.max_elements", 3000000)

# 设置页面
st.set_page_config(page_title="网点现金分析", layout="wide")
st.set_page_config(
    page_title="网点数据分析",
    page_icon="🏦",
    layout="wide",
    initial_sidebar_state="collapsed"
)

hide_streamlit_style = """
    <style>
    #MainMenu {visibility: hidden;}
    footer {visibility: hidden;}
    .st-emotion-cache-4z1n4l.erv3yhi2 {
        display: none;
    }
    .st-emotion-cache-scp8yw.e3g0k5y6 {
        display: none;
    }
    </style>
"""

st.markdown(hide_streamlit_style, unsafe_allow_html=True)

# 自定义标题
st.markdown("""
    <h1 style='text-align: center; color: #1f77b4; margin-bottom: 30px;'>
        网点现金交易数据分析
    </h1>
""", unsafe_allow_html=True)


# 数据加载函数
@st.cache_data
def load_data():
    """数据加载函数 - 从CSV文件或上传文件加载数据"""
    try:
        file_path = "pages/branch.csv"  # 网点数据文件
        if os.path.exists(file_path):
            df = pd.read_csv(file_path)
            return df
    except Exception as e:
        st.warning(f"CSV文件加载失败: {e}")

    uploaded_file = st.sidebar.file_uploader(
        "上传网点数据文件",
        type=['csv'],
        help="支持CSV格式文件"
    )

    if uploaded_file is not None:
        try:
            df = pd.read_csv(uploaded_file)
            return df
        except Exception as e:
            st.error(f"文件读取错误: {e}")
            return None
    return None


# 数据预处理函数
def preprocess_data(df):
    """数据清洗和预处理"""
    df_clean = df.copy()

    # 转换日期格式
    df_clean['交易日期'] = pd.to_datetime(df_clean['交易日期'], format='%Y%m%d', errors='coerce')

    # 确保数值列是数值类型
    numeric_cols = ['柜面现金存款', '柜面现金取款', '现金预约款', '柜面实时库存']
    for col in numeric_cols:
        df_clean[col] = pd.to_numeric(df_clean[col], errors='coerce')

    # 计算衍生指标
    df_clean['净现金流'] = df_clean['柜面现金存款'] - df_clean['柜面现金取款']
    df_clean['现金周转率'] = (df_clean['柜面现金取款'] / df_clean['柜面实时库存']).fillna(0)
    df_clean['预约款占比'] = (df_clean['现金预约款'] / (df_clean['柜面现金取款'] + 1)).fillna(0)  # 避免除零

    # 添加月份和星期信息
    df_clean['月份'] = df_clean['交易日期'].dt.month
    df_clean['星期'] = df_clean['交易日期'].dt.day_name()

    # 处理可能的空值
    df_clean = df_clean.dropna(subset=numeric_cols)

    return df_clean


# 优化数据显示函数
def display_dataframe_with_limit(df, max_rows=1000, height=400):
    """优化数据显示，限制行数避免性能问题"""
    if len(df) > max_rows:
        st.warning(f"数据量较大，仅显示前 {max_rows} 条记录（共 {len(df):,} 条）")
        display_df = df.head(max_rows)
    else:
        display_df = df

    st.dataframe(
        display_df,
        use_container_width=True,
        height=height
    )


# 主程序
def main():
    # 加载数据
    df_raw = load_data()

    if df_raw is None:
        st.error("无法加载数据，请上传CSV文件或确保当前目录下存在branch.csv文件")
        st.info("请使用左侧边栏的文件上传功能上传数据文件")
        return

    # 显示原始数据信息
    with st.expander("数据概览", expanded=False):
        col1, col2, col3 = st.columns(3)
        with col1:
            st.metric("总记录数", f"{len(df_raw):,}")
        with col2:
            st.metric("网点数量", df_raw['机构名称'].nunique())
        with col3:
            st.metric("数据日期范围",
                      f"{df_raw['交易日期'].iloc[0]} 至 {df_raw['交易日期'].iloc[-1]}"
                      if len(df_raw) > 0 else "无数据")

        st.write("数据预览（前1000条）:")
        display_dataframe_with_limit(df_raw, max_rows=1000, height=300)

    # 数据预处理
    df = preprocess_data(df_raw)

    # 侧边栏筛选器
    st.sidebar.header("数据筛选")

    # 日期范围筛选
    if len(df) > 0:
        min_date = df['交易日期'].min()
        max_date = df['交易日期'].max()

        date_range = st.sidebar.date_input(
            "选择日期范围",
            [min_date, max_date],
            min_value=min_date,
            max_value=max_date
        )
    else:
        date_range = [datetime.now(), datetime.now()]
        st.sidebar.warning("无有效数据")

    # 获取所有网点
    all_branches = df['机构名称'].unique() if len(df) > 0 else []

    # 使用session state来跟踪网点选择
    if 'selected_branches' not in st.session_state:
        # 默认选择前10个网点
        st.session_state.selected_branches = all_branches[:min(10, len(all_branches))].tolist()

    # 网点筛选 - 使用key来确保状态同步
    selected_branches = st.sidebar.multiselect(
        "选择网点名称",
        options=all_branches,
        default=st.session_state.selected_branches,
        help="默认选择前10个网点，可多选或取消选择",
        key="branch_selector"
    )

    # 立即检查选择是否变化，如果变化就更新session state并重新运行
    if selected_branches != st.session_state.selected_branches:
        st.session_state.selected_branches = selected_branches
        st.rerun()

    # 应用筛选
    if len(df) > 0 and len(date_range) == 2:
        # 基础日期筛选
        date_filtered = df[
            (df['交易日期'] >= pd.to_datetime(date_range[0])) &
            (df['交易日期'] <= pd.to_datetime(date_range[1]))
        ]

        # 网点筛选
        if st.session_state.selected_branches:
            filtered_df = date_filtered[date_filtered['机构名称'].isin(st.session_state.selected_branches)]
        else:
            filtered_df = date_filtered
    else:
        filtered_df = df

    # 显示筛选结果信息
    st.sidebar.header("筛选状态")
    if len(st.session_state.selected_branches) == 0:
        st.sidebar.info("🏦 所有网点")
    else:
        st.sidebar.info(f"🏦 {len(st.session_state.selected_branches)} 个网点")

    st.sidebar.info(f"📊 筛选后记录: {len(filtered_df):,}")

    # 显示当前选择的网点（前3个）
    if len(st.session_state.selected_branches) > 0:
        st.sidebar.write("**当前选择的网点:**")
        for i, branch in enumerate(st.session_state.selected_branches[:3]):
            st.sidebar.write(f"• {branch}")
        if len(st.session_state.selected_branches) > 3:
            st.sidebar.write(f"• ... 还有 {len(st.session_state.selected_branches) - 3} 个网点")

    # 主显示区域 - 关键指标
    st.header("关键指标")

    if len(filtered_df) == 0:
        st.warning("没有符合筛选条件的数据，请调整筛选条件")
        return

    # 第一行指标
    col1, col2, col3, col4 = st.columns(4)

    with col1:
        total_deposit = filtered_df['柜面现金存款'].sum()
        avg_deposit = filtered_df['柜面现金存款'].mean()
        st.metric("总存款", f"¥{total_deposit:,.0f}",
                  delta=f"¥{avg_deposit:,.0f} 日均" if not pd.isna(avg_deposit) else None)

    with col2:
        total_withdrawal = filtered_df['柜面现金取款'].sum()
        avg_withdrawal = filtered_df['柜面现金取款'].mean()
        st.metric("总取款", f"¥{total_withdrawal:,.0f}",
                  delta=f"¥{avg_withdrawal:,.0f} 日均" if not pd.isna(avg_withdrawal) else None)

    with col3:
        total_reservation = filtered_df['现金预约款'].sum()
        avg_reservation = filtered_df['现金预约款'].mean()
        st.metric("总预约款", f"¥{total_reservation:,.0f}",
                  delta=f"¥{avg_reservation:,.0f} 日均" if not pd.isna(avg_reservation) else None)

    with col4:
        avg_inventory = filtered_df['柜面实时库存'].mean()
        st.metric("平均库存", f"¥{avg_inventory:,.0f}")

    # 第二行指标
    col5, col6, col7, col8 = st.columns(4)

    with col5:
        net_cash_flow = filtered_df['净现金流'].sum()
        st.metric("净现金流", f"¥{net_cash_flow:,.0f}")

    with col6:
        utilization_rate = filtered_df['现金周转率'].mean() * 100
        st.metric("平均现金周转率", f"{utilization_rate:.1f}%")

    with col7:
        reservation_ratio = filtered_df['预约款占比'].mean() * 100
        st.metric("平均预约款占比", f"{reservation_ratio:.1f}%")

    with col8:
        # 计算每个网点的交易天数，然后求和
        branch_operating_days = filtered_df.groupby('机构名称')['交易日期'].nunique().sum()
        st.metric("网点总运营天数", f"{branch_operating_days:,}")

    # 可视化分析
    st.header("可视化分析")

    tab1, tab2, tab3, tab4, tab5 = st.tabs(["交易概览", "网点分析", "趋势分析", "库存分析", "详细数据"])

    with tab1:
        col1, col2 = st.columns(2)

        with col1:
            st.subheader("交易类型对比")
            summary_data = filtered_df[['柜面现金存款', '柜面现金取款', '现金预约款']].sum()
            st.bar_chart(summary_data)

        with col2:
            st.subheader("现金周转率分布")
            try:
                import plotly.express as px
                if len(filtered_df) > 10000:
                    sample_df = filtered_df.sample(n=10000, random_state=42)
                    st.info(f"数据量较大，随机采样 10,000 条记录进行可视化")
                else:
                    sample_df = filtered_df

                fig = px.histogram(sample_df, x='现金周转率',
                                   nbins=20, title="现金周转率分布")
                st.plotly_chart(fig, use_container_width=True)
            except Exception as e:
                st.info(f"启用Plotly以获得更好的可视化效果: {e}")

    with tab2:
        st.subheader("各网点交易情况")

        # 按网点汇总
        branch_summary = filtered_df.groupby('机构名称').agg({
            '柜面现金存款': 'sum',
            '柜面现金取款': 'sum',
            '现金预约款': 'sum',
            '柜面实时库存': 'mean',
            '净现金流': 'sum',
            '交易日期': 'count'
        }).rename(columns={'交易日期': '交易天数'}).reset_index()

        # 显示网点排名表格
        st.dataframe(
            branch_summary.style.format({
                '柜面现金存款': '¥{:,.0f}',
                '柜面现金取款': '¥{:,.0f}',
                '现金预约款': '¥{:,.0f}',
                '柜面实时库存': '¥{:,.0f}',
                '净现金流': '¥{:,.0f}'
            }),
            use_container_width=True,
            height=400
        )

        # 网点取款排名图表
        col1, col2 = st.columns(2)
        with col1:
            try:
                import plotly.express as px
                top_branches = branch_summary.nlargest(10, '柜面现金取款')
                fig = px.bar(top_branches, x='机构名称', y='柜面现金取款',
                             title="取款金额TOP10网点")
                fig.update_layout(xaxis_tickangle=-45)
                st.plotly_chart(fig, use_container_width=True)
            except Exception as e:
                st.bar_chart(branch_summary.set_index('机构名称')['柜面现金取款'])

        with col2:
            try:
                fig = px.pie(branch_summary.nlargest(8, '柜面现金取款'),
                             values='柜面现金取款', names='机构名称',
                             title="取款金额分布")
                st.plotly_chart(fig, use_container_width=True)
            except Exception as e:
                st.info(f"饼图需要Plotly支持: {e}")

    with tab3:
        st.subheader("时间趋势分析")

        # 按日期汇总
        daily_summary = filtered_df.groupby('交易日期').agg({
            '柜面现金存款': 'sum',
            '柜面现金取款': 'sum',
            '现金预约款': 'sum',
            '净现金流': 'sum'
        }).reset_index()

        if len(daily_summary) > 0:
            st.line_chart(daily_summary.set_index('交易日期')[['柜面现金存款', '柜面现金取款', '现金预约款']])

            # 净现金流趋势
            st.subheader("净现金流趋势")
            st.area_chart(daily_summary.set_index('交易日期')['净现金流'])
        else:
            st.warning("无时间序列数据可展示")

    with tab4:
        st.subheader("库存分析")

        # 库存相关分析
        inventory_analysis = filtered_df.groupby('机构名称').agg({
            '柜面实时库存': ['mean', 'std', 'min', 'max'],
            '柜面现金取款': 'mean'
        }).round(0)
        inventory_analysis.columns = ['平均库存', '库存标准差', '最小库存', '最大库存', '日均取款']
        inventory_analysis = inventory_analysis.reset_index()

        st.dataframe(
            inventory_analysis.style.format({
                '平均库存': '¥{:,.0f}',
                '库存标准差': '¥{:,.0f}',
                '最小库存': '¥{:,.0f}',
                '最大库存': '¥{:,.0f}',
                '日均取款': '¥{:,.0f}'
            }),
            use_container_width=True,
            height=400
        )

        # 库存与取款关系分析
        try:
            import plotly.express as px
            fig = px.scatter(branch_summary, x='平均库存', y='柜面现金取款',
                             size='柜面现金取款', hover_name='机构名称',
                             title="库存与取款关系分析")
            st.plotly_chart(fig, use_container_width=True)
        except Exception as e:
            st.info(f"散点图需要Plotly支持: {e}")

    with tab5:
        st.subheader("详细交易数据")

        # 显示详细数据表格
        display_columns = ['交易日期', '机构名称', '机构编号',
                           '柜面现金存款', '柜面现金取款', '现金预约款',
                           '柜面实时库存', '净现金流']

        display_data = filtered_df[display_columns]
        display_dataframe_with_limit(display_data, max_rows=1000, height=400)

        # 数据下载功能
        if len(filtered_df) > 100000:
            st.warning("数据量较大，下载可能需要一些时间...")

        csv = filtered_df.to_csv(index=False, encoding='utf-8-sig')
        st.download_button(
            label=f"下载筛选数据 (CSV, {len(filtered_df):,} 条记录)",
            data=csv,
            file_name=f"网点交易数据_{datetime.now().strftime('%Y%m%d_%H%M')}.csv",
            mime="text/csv"
        )


if __name__ == "__main__":
    main()